var LatticeCanvas = function(canvas, ops) {
	if (canvas && canvas.getContext) {
		// 画布
		this.canvas = canvas;
		this.ctx = this.canvas.getContext("2d");
		// 基本属性
		this.width = canvas.width;
		this.height = canvas.height;
		this.imgLeft = 0;
		this.imgTop = 0;
		this.rows = 0;
		this.columns = 0;
		this.rowHeight = 0;
		this.columnWidth = 0;
		this.selectedPoints = {};
		this.imgDatas = {};
		// 图片
		this.img = new Image();

		// 自定义属性
		var op = ops || {};
		// 栅格覆盖区域，'image' || 'canvas'
		this.lattice = op.lattice || 'canvas';
		// 点击区域颜色是否反转
		this.reverse = op.reverse || false;
		// 点击区域指定颜色交替变换
		this.colors = op.colors || ["rgba(255,0,0,0.8)", "rgba(76, 171, 76, 0.8)", "grey"];
		// 绘制图片边界
		this.drawImgBorder = op.drawImgBorder || false;
		// 模式 切图/栅格 qt || sg
		this.model = op.model || 'sg';
		// 点击某区域
		this.areaclick = op.areaclick;
		// 绑定事件
		this.bindEvent();
		// 初始化
		this.init();
	}
}, 
// 工具类
LytUtils = {
	// 数组、对象迭代器
	eachFun: function(o, fn) {
		var argType = Object.prototype.toString.call(o);
		if (argType == '[object Array]') {
			var i = 0, len = o.length;
			for (; i < len; i++) {
				if (fn.call(o[i], i, o[i])) {
					break;
				}
			}
		} else if (argType == '[object Object]') {
			for (var key in o) {
				if (fn.call(o[key], key, o[key])) {
					break;
				}
			}
		} else {
			throw new Error("无法遍历的数据类型");
		}
	},
	// 节流器
	throttle: function() {
		var isClear = arguments[0], fn;
		if (typeof isClear === 'boolean') {
			fn = arguments[1];
			fn.__throttleId && clearTimeout(fn.__throttleId);
		} else {
			fn = isClear;
			var param = arguments[1], p = $.extend({
				context: null,
				args: [],
				time: 300
			}, param);
			arguments.callee(true, fn);
			fn.__throttleId = setTimeout(function() {
				fn.apply(p.context, p.args);
			}, p.time);
		}
	}
};

LatticeCanvas.prototype = {
	bindEvent: function() {
		var c = this, canvas = c.canvas,
		// 获取行、列位置
		getPosition = function(e) {
			var rect = canvas.getBoundingClientRect();
			// 鼠标相对画布位置
			var position = {
				x: e.clientX - rect.left * (c.width / rect.width),
				y: e.clientY - rect.top * (c.height / rect.height)
			},
			// 行下标
			rowIndex = Math.floor((position.y - c.imgTop) / c.rowHeight),
			// 列下标
			columnIndex = Math.floor((position.x - c.imgLeft) / c.columnWidth);
			// 无效区域返回undefined
			if (rowIndex < 0 || columnIndex < 0) {
				return undefined;
			};
			return {
				rowIndex: rowIndex,
				columnIndex: columnIndex
			};
		},
		// 获取事件区域
		getEventPosition = function(e) {
			if (!c.rows || !c.columns) {
				return false;
			}
			var p = getPosition(e);
			if (!p || p.rowIndex < 0 || p.columnIndex < 0) {
				return false;
			}
			return p;
		};
		// 绑定鼠标点击事件
		canvas.onclick = function(e) {
			var p = getEventPosition(e);
			if (!p) {
				return false;
			}
			if (c.areaclick) {
				c.areaclick.call(c, p.rowIndex, p.columnIndex, c.selectedPoints[p.rowIndex] && c.selectedPoints[p.rowIndex][p.columnIndex]);
				return false;
			}
			// 根据记录判断选中还是取消
			if (!c.selectedPoints[p.rowIndex] || !c.selectedPoints[p.rowIndex][p.columnIndex]) {
				c.select(p.rowIndex, p.columnIndex);
			} else {
				c.revert(p.rowIndex, p.columnIndex);
			}
			return false;
		};
		// 绑定鼠标移动事件
		canvas.onmousemove = function(e) {
			var p = getEventPosition(e);
			if (!p) {
				return false;
			}
			// 改变相应的鼠标指针样式
			if (!c.selectedPoints[p.rowIndex] || !c.selectedPoints[p.rowIndex][p.columnIndex]) {
				canvas.style.cursor = 'default';
			} else {
				canvas.style.cursor = 'pointer';
			}
			return false;
		};
	},
	// 初始化，首先检测浏览器是否支持canvas，不支持时不做任何操作
	init: function() {
		var c = this;
		c.imgLoaded = false;
		c.img.onload = function() {
			if (!c.ctx) {
				return false;
			}
			c.ctx.clearRect(0, 0, c.width, c.height);
			c.imgLeft = 0;
			c.imgTop = 0;
			c.rows = 0;
			c.columns = 0;
			c.selectedPoints = {};
			c.imgDatas = {};
			c.drawImage();
		}
	},
	clear: function() {
		var c = this;
		c.ctx.clearRect(0, 0, c.width, c.height);
		c.imgLeft = 0;
		c.imgTop = 0;
		c.rows = 0;
		c.columns = 0;
		c.selectedPoints = {};
		c.imgDatas = {};
	},
	// 加载图片
	loadImg: function(src) {
		this.imgLoaded = false;
		this.img.src = src;
	},
	// 重新加载图片
	reloadImg: function() {
		this.imgLoaded = false;
		if (this.img.src) {
			var src = this.img.src;
			this.img = new Image();
			this.init();
			this.img.src = src;
		}
	},
	// 绘制图片背景
	drawImage: function() {
		var c = this, img = this.img, w = this.width, h = this.height, maxBorder = '', max = 0, proportion = 0;
		// 图片大小和画布尺寸不等时，采用同步缩放
		if (img.naturalWidth != w || img.naturalHeight != h) {
			// 比较长宽比，
			if (w / h > img.naturalWidth / img.naturalHeight) {
				max = img.naturalHeight;
				maxBorder = 'height';
			} else {
				max = img.naturalWidth;
				maxBorder = 'width';
			}
		}
		var width = w, height = h;
		// 计算等比缩放之后的宽、高
		if (max) {
			if (maxBorder == 'width') {
				proportion = max / w;
				height = img.naturalHeight / proportion;
				if (c.lattice === 'image') {
					this.imgTop = (h - height) / 2;
				}
			} else {
				proportion = max / h;
				width = img.naturalWidth / proportion;
				if (c.lattice === 'image') {
					this.imgLeft = (w - width) / 2;
				}
			}
		}
		// 将图片等比缩放后居中绘制
		this.ctx.drawImage(img, 0, 0, img.naturalWidth, img.naturalHeight, Math.round((w - width) / 2), Math.round((h - height) / 2), width, height);
		// 如果图片大小和画布大小不等，绘制图片边界线
		if ((width != w || height != h) && this.drawImgBorder) {
			this._drawImageBorder(Math.round((w - width) / 2), Math.round((h - height) / 2));
		}
		c.imgLoaded = true;
	},
	_drawImageBorder: function(x, y) {
		if (x === 0 && y === 0) {
			return false;
		}
		this.ctx.beginPath();
		this.ctx.setLineDash([4, 2]);
		this.ctx.lineWidth = 1;
		if (x === 0) {
			y = Math.round(y) - 0.5;
			// 画两条横线
			this.ctx.moveTo(0, y);
			this.ctx.lineTo(this.width, y);
			this.ctx.moveTo(0, this.height - y);
			this.ctx.lineTo(this.width, this.height - y);
		} else {
			x = Math.round(x) - 0.5;
			// 画纵边界线
			this.ctx.moveTo(x, 0);
			this.ctx.lineTo(x, this.height);
			this.ctx.moveTo(this.width - x - 1, 0);
			this.ctx.lineTo(this.width - x - 1, this.height);
		}
		// 绘制的颜色
		this.ctx.strokeStyle = 'rgba(255, 0, 0, 0.8)';
		// 绘制边框
		this.ctx.stroke();
	},
	// 异步执行器，必须在图片加载完之后执行
	asyncExecution: function(execute) {
		if (typeof execute !== 'function') {
			return false;
		}
		var c = this, args = Array.prototype.slice.call(arguments, 1);
		setTimeout(function() {
			if (c.imgLoaded) {
				execute.apply(c, args);
			} else {
				args.unshift(execute);
				c.asyncExecution.apply(c, args);
			}
		}, 20);
	},
	// 绘制栅格
	drawLattice: function(rows, columns) {
		this.asyncExecution(this._drawLattice, rows, columns);
	},
	// 重新绘制栅格
	redrawLattice: function(rows, columns) {
		if (!this.img.src) {
			return false;
		}
		this.reloadImg();
		this.drawLattice(rows, columns);
	},
	// 设置行列属性
	setRowsAndColumns: function(rows, columns) {
		this.rows = rows;
		this.columns = columns;
		this.rowHeight = (this.height - 2 * this.imgTop) / rows;
		this.columnWidth = (this.width - 2 * this.imgLeft) / columns;
	},
	// 绘制栅格
	_drawLattice: function(rows, columns) {
		if (!this.img.src) {
			this.ctx.clearRect(0, 0, this.width, this.height);
		}
		this.setRowsAndColumns(rows, columns);
		// imgLeft为0时，需要画columns - 1条纵线，否则columns + 1条纵线；imgTop为0时，需要画rows - 1条横线，否则rows + 1条横线
		var reviseRow = this.imgTop === 0 ? 1 : 0, reviseColumn = this.imgLeft === 0 ? 1 : 0, ctx = this.ctx;
		ctx.beginPath();
		// 线宽（奇数时需要修正-0.5像素，偶数时不用修正）
		ctx.lineWidth = 1;
		this.ctx.setLineDash([0]);
		var reviseWidth = 0.5;
		// 设置虚线样式
		// ctx.setLineDash([7, 3]);
		// 绘制横线，起点x为imgLeft，止点x为(w - imgLeft)
		for (var rowIndex = 0; rowIndex < (reviseRow === 0 ? rows + 1 : rows - 1); rowIndex++) {
			ctx.moveTo(this.imgLeft, Math.round(((this.height - 2 * this.imgTop) / rows) * (rowIndex + reviseRow)) + this.imgTop - reviseWidth);
			ctx.lineTo(this.width - this.imgLeft, Math.round(((this.height - 2 * this.imgTop) / rows) * (rowIndex + reviseRow)) + this.imgTop - reviseWidth);
		}
		// 绘制纵线，起点y为imgTop，止点y为(h - imgTop)
		for (var columnIndex = 0; columnIndex < (reviseColumn == 0 ? columns + 1 : columns - 1); columnIndex++) {
			ctx.moveTo(Math.round(((this.width - 2 * this.imgLeft) / columns) * (columnIndex + reviseColumn)) + this.imgLeft - reviseWidth, this.imgTop);
			ctx.lineTo(Math.round(((this.width - 2 * this.imgLeft) / columns) * (columnIndex + reviseColumn)) + this.imgLeft - reviseWidth, this.height - this.imgTop);
		}
		// 绘制的颜色
		ctx.strokeStyle = '#d8dfe5';
		// 绘制边框
		ctx.stroke();
	},
	// 区域颜色反转
	_reverseImgData: function(rowIndex, columnIndex) {
		var ctx = this.ctx, x = this._getAreaLeft(columnIndex), y = this._getAreaTop(rowIndex);
		var imgData = ctx.getImageData(x, y, Math.round(this.columnWidth), Math.round(this.rowHeight)), data = imgData.data;
		for (var i = 0; i < data.length; i += 4) {
			data[i] = 255 - data[i]; // r
			data[i + 1] = 255 - data[i + 1]; // g
			data[i + 2] = 255 - data[i + 2]; // b
		}
		this.ctx.putImageData(imgData, x, y);
	},
	// 获取点击区域左上角x标
	_getAreaLeft: function(columnIndex) {
		return Math.round(this.columnWidth * columnIndex + this.imgLeft);
	},
	// 获取点击区域左上角y标
	_getAreaTop: function(rowIndex) {
		return Math.round(this.rowHeight * rowIndex + this.imgTop);
	},
	_isAreaSelected: function(rowIndex, columnIndex) {
		return this.selectedPoints[rowIndex] && this.selectedPoints[rowIndex][columnIndex];
	},
	selectPoint: function(rowIndex, columnIndex) {
		// 记录选中的位置
		if (!this.selectedPoints[rowIndex]) {
			this.selectedPoints[rowIndex] = {};
		}
		this.selectedPoints[rowIndex][columnIndex] = true;
	},
	// 选中相应的区域
	select: function(rowIndex, columnIndex) {
		// 如果该区域已经选中
		if (this._isAreaSelected(rowIndex, columnIndex)) {
			return false;
		}
		this.selectPoint(rowIndex, columnIndex);
		// 改变鼠标指针
		this.canvas.style.cursor = 'pointer';
		if (this.model === 'qt') {
			this._selectQt(rowIndex, columnIndex);
		} else if (this.reverse) {
			this._reverseImgData(rowIndex, columnIndex);
		} else {
			var ctx = this.ctx, x = this._getAreaLeft(columnIndex), y = this._getAreaTop(rowIndex);
			if (!this.imgDatas[rowIndex]) {
				this.imgDatas[rowIndex] = {};
			}
			// 记录该位置的imgData
			this.imgDatas[rowIndex][columnIndex] = ctx.getImageData(x, y, Math.round(this.columnWidth), Math.round(this.rowHeight));
			var color = this.colors[(rowIndex + columnIndex) % this.colors.length];
			ctx.beginPath();
			ctx.fillStyle = color;
			ctx.fillRect(x, y, this.columnWidth, this.rowHeight);
		}
	},
	// 绘制矩形
	fillRect: function(rowIndex, columnIndex, color) {
		var c = this, ctx = this.ctx, x = this._getAreaLeft(columnIndex), y = this._getAreaTop(rowIndex);
		if (c.imgDatas[rowIndex] && c.imgDatas[rowIndex][columnIndex]) {
			ctx.putImageData(c.imgDatas[rowIndex][columnIndex], x, y);
		}
		ctx.beginPath();
		ctx.fillStyle = color;
		ctx.fillRect(x, y, c.columnWidth, c.rowHeight);
	},
	_selectQt: function(rowIndex, columnIndex) {
		if (!this.selectedPoint || this.selectedPoint.r === undefined) {
			this.selectedPoint = {
				r: rowIndex,
				c: columnIndex
			}
			this._reverseImgData(rowIndex, columnIndex);
		} else {
			this._reverseImgData(this.selectedPoint.r, this.selectedPoint.c);
			this._swapPosition(this.selectedPoint, {
				r: rowIndex,
				c: columnIndex
			});
			delete this.selectedPoints[this.selectedPoint.r][this.selectedPoint.c];
			delete this.selectedPoint;
			delete this.selectedPoints[rowIndex][columnIndex];
			this.canvas.style.cursor = 'default';
		}
	},
	// 还原相应的区域
	revert: function(rowIndex, columnIndex) {
		// 如果该区域没有选中
		if (!this._isAreaSelected(rowIndex, columnIndex)) {
			return false;
		}
		// 删除选中的位置
		delete this.selectedPoints[rowIndex][columnIndex];
		// 改变鼠标指针
		this.canvas.style.cursor = 'default';

		if (this.model === 'qt') {
			this._revertQt(rowIndex, columnIndex);
		} else if (this.reverse) {
			this._reverseImgData(rowIndex, columnIndex);
		} else {
			var ctx = this.ctx, x = this._getAreaLeft(columnIndex), y = this._getAreaTop(rowIndex);
			// 还原该位置的imgData
			ctx.putImageData(this.imgDatas[rowIndex][columnIndex], x, y);
			delete this.imgDatas[rowIndex][columnIndex];
		}
		return true;
	},
	_revertQt: function(rowIndex, columnIndex) {
		this._reverseImgData(rowIndex, columnIndex);
		delete this.selectedPoint;
		this.canvas.style.cursor = 'default';
	},
	// 绑定到指定的图片文件选择框
	bindFileInput: function(fileInput) {
		var c = this;
		// 文件改变时触发画布重新加载图片
		fileInput.onchange = function() {
			var file = fileInput.files[0];
			// 文件类型或文件名长度不符
			if (!file || !file.type.match(/image.*/) || file.name.length > 60) {
				c.clear();
				return false;
			}
			var reader = new FileReader();
			reader.onloadend = (function() {
				return function(e) {
					c.loadImg(e.target.result);
				}
			})();
			reader.readAsDataURL(file);
		};
		fileInput.onchange.apply(fileInput);
	},
	// 切图并打乱
	slicePicture: function(rows, columns) {
		if (!this.img.src) {
			return false;
		}
		if (rows < 2 || columns < 2) {
			return false;
		}
		this.reloadImg();
		this.asyncExecution(function() {
			this.setRowsAndColumns(rows, columns);
			this._chaos();
		}, rows, columns)
	},
	// 打乱顺序
	_chaos: function() {
		var c = this;
		c.realPositions = [];
		for (var rowIndex = 0; rowIndex < c.rows; rowIndex++) {
			c.realPositions[rowIndex] = [];
			for (var columnIndex = 0; columnIndex < c.columns; columnIndex++) {
				c.realPositions[rowIndex][columnIndex] = {
					r: rowIndex,
					c: columnIndex
				};
			}
		}
		var getRandomPoint = function() {
			return {
				r: Math.floor(Math.random() * c.rows),
				c: Math.floor(Math.random() * c.columns)
			}
		};
		var len = c.rows * c.columns;
		for (var index = 0; index < len; index++) {
			var point1 = getRandomPoint(), point2 = getRandomPoint();
			while (point1.r === point2.r && point1.c === point2.c) {
				point2 = getRandomPoint();
			}
			c._swapPosition(point1, point2);
		}
	},
	// 交换位置
	_swapPosition: function(point1, point2) {
		// 点1位置
		var x1 = Math.round(point1.c * this.columnWidth + this.imgLeft), y1 = Math.round(point1.r * this.rowHeight + this.imgTop),
		// 点2位置
		x2 = Math.round(point2.c * this.columnWidth + this.imgLeft), y2 = Math.round(point2.r * this.rowHeight + this.imgTop);
		// 区域位置交换
		var imgData = this.ctx.getImageData(x1, y1, Math.round(this.columnWidth), Math.round(this.rowHeight));
		this.ctx.putImageData(this.ctx.getImageData(x2, y2, Math.round(this.columnWidth), Math.round(this.rowHeight)), x1, y1);
		this.ctx.putImageData(imgData, x2, y2);
		// 位置交换
		var p1 = new Object(this.realPositions[point1.r][point1.c]), p2 = new Object(this.realPositions[point2.r][point2.c]);
		this.realPositions[point1.r][point1.c] = p2;
		this.realPositions[point2.r][point2.c] = p1;
	}
};